package com.shiehub.sdk.opengw.encrypt;


import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
import org.apache.commons.lang.ArrayUtils;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

/**
 * @Description: RSA非对称型加密的公钥和私钥
 * @Author: guoleijie@shie.com.cn
 * @Since:2016-9-12
 */
public class RSAUtils {

  public static final String SIGNATURE_ALGORITHM = "SHA1withRSA";
  public static final String ENCODEDING = "UTF-8";
  private static int keyLength = 1024;
  private KeyPairGenerator kpg = null;
  private KeyPair kp = null;
  private PublicKey public_key = null;
  private PrivateKey private_key = null;

  /**
   * @Description:初始化方法，获得秘钥对
   * @ReturnType
   * @Since:2016年9月12日 15:25:00
   */
  public RSAUtils(String address)
      throws NoSuchAlgorithmException, FileNotFoundException, IOException {
    kpg = KeyPairGenerator.getInstance("RSA"); // 创建‘密钥对’生成器
    kpg.initialize(keyLength); // 指定密钥长度（取值范围：512～2048）
    kp = kpg.genKeyPair(); // 生成‘密钥对’，其中包含着一个公钥和一个私钥的信息
    public_key = kp.getPublic(); // 获得公钥
    private_key = kp.getPrivate(); // 获得私钥

    BASE64Encoder b64 = new BASE64Encoder();
    String pkStr = b64.encode(public_key.getEncoded());
    String prStr = b64.encode(private_key.getEncoded());
    FileWriter fw = new FileWriter(address + "/private_key.dat");
    fw.write(prStr);
    fw.close();

    FileWriter fw2 = new FileWriter(address + "/public_key.dat");
    fw2.write(pkStr);
    fw2.close();
  }

  public static String[] createKeyPairs() {
    try {
      KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); // 创建‘密钥对’生成器
      kpg.initialize(keyLength); // 指定密钥长度（取值范围：512～2048）
      KeyPair kp = kpg.genKeyPair(); // 生成‘密钥对’，其中包含着一个公钥和一个私钥的信息
      PublicKey public_key = kp.getPublic(); // 获得公钥
      PrivateKey private_key = kp.getPrivate(); // 获得私钥
      BASE64Encoder b64 = new BASE64Encoder();
      String pkStr = b64.encode(public_key.getEncoded());
      String prStr = b64.encode(private_key.getEncoded());
      String[] keyPairs = new String[]{pkStr, prStr};
      return keyPairs;
    } catch (Exception e) {

    }
    return null;
  }

  /**
   * @Description:私钥加密
   * @ReturnType: String
   * @Since:2016年9月12日 15:25:00
   * @Author: guoleijie@shie.com.cn
   */
  public static String privateEncrypt(String strPrivateKey, String source) throws Exception {
    BASE64Decoder b64d = new BASE64Decoder();
    byte[] keyByte = b64d.decodeBuffer(strPrivateKey);
    PKCS8EncodedKeySpec s8ek = new PKCS8EncodedKeySpec(keyByte);
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    PrivateKey privateKey = keyFactory.generatePrivate(s8ek);
    Cipher cipher = Cipher.getInstance("RSA");
    cipher.init(Cipher.ENCRYPT_MODE, privateKey);
    byte[] sbt = source.getBytes(ENCODEDING);
//		byte[] epByte = cipher.doFinal(sbt);
    byte[] epByte = null;
    for (int i = 0; i < sbt.length; i += 64) { // 注意要使用2的倍数，否则会出现加密后的内容再解密时为乱码
      byte[] doFinal = cipher.doFinal(ArrayUtils.subarray(sbt, i, i + 64));
      epByte = ArrayUtils.addAll(epByte, doFinal);
    }
    BASE64Encoder encoder = new BASE64Encoder();
    String epStr = encoder.encode(epByte);
    return epStr;

  }

  /**
   * @Description:私钥解密
   * @ReturnType: String
   * @Since:2016年9月12日 15:25:00
   * @Author: guoleijie@shie.com.cn
   */
  public static String privateDecrypt(String priKey, String contextInfo) throws Exception {
    BASE64Decoder b64d = new BASE64Decoder();
    byte[] keyByte = b64d.decodeBuffer(priKey);
    PKCS8EncodedKeySpec s8ek = new PKCS8EncodedKeySpec(keyByte);
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    PrivateKey privateKey = keyFactory.generatePrivate(s8ek);

    /** 得到Cipher对象对已用公钥加密的数据进行RSA解密 */
    Cipher cipher = Cipher.getInstance("RSA");
    cipher.init(Cipher.DECRYPT_MODE, privateKey);
    BASE64Decoder decoder = new BASE64Decoder();
    byte[] b1 = decoder.decodeBuffer(contextInfo);
    /** 执行解密操作 */
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < b1.length; i += cipher.getOutputSize(0)) {
      byte[] doFinal = cipher.doFinal(ArrayUtils.subarray(b1, i, i + cipher.getOutputSize(0)));
      sb.append(new String(doFinal));
    }
    String dataReturn = sb.toString();
//		byte[] b = cipher.doFinal(b1);
    return dataReturn;
  }

  /**
   * 公钥加密
   *
   * @Since:2016年9月12日 16:25:00
   * @Author: guoleijie@shie.com.cn
   */
  public static String publicEncrypt(String strPublicKey, String source) throws Exception {
    BASE64Decoder b64d = new BASE64Decoder();
    byte[] keyByte = b64d.decodeBuffer(strPublicKey);
    X509EncodedKeySpec x509ek = new X509EncodedKeySpec(keyByte);
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    PublicKey publicKey = keyFactory.generatePublic(x509ek);
    Cipher cipher = Cipher.getInstance("RSA");
    cipher.init(Cipher.ENCRYPT_MODE, publicKey);
    byte[] sbt = source.getBytes(ENCODEDING);
    byte[] enBytes = null;
    for (int i = 0; i < sbt.length; i += 64) { // 注意要使用2的倍数，否则会出现加密后的内容再解密时为乱码
      byte[] doFinal = cipher.doFinal(ArrayUtils.subarray(sbt, i, i + 64));
      enBytes = ArrayUtils.addAll(enBytes, doFinal);
    }
    BASE64Encoder encoder = new BASE64Encoder();
    String epStr = encoder.encode(enBytes);
    return epStr;
  }

  /**
   * 公钥解密
   *
   * @Author: guoleijie@shie.com.cn
   */
  public static String publicDecrypt(String strPublicKey, String contextInfo) throws Exception {
    BASE64Decoder b64d = new BASE64Decoder();
    byte[] keyByte = b64d.decodeBuffer(strPublicKey);
    X509EncodedKeySpec x509ek = new X509EncodedKeySpec(keyByte);
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    PublicKey publicKey = keyFactory.generatePublic(x509ek);
    /** 得到Cipher对象对已用公钥加密的数据进行RSA解密 */
    Cipher cipher = Cipher.getInstance("RSA");
    cipher.init(Cipher.DECRYPT_MODE, publicKey);
    BASE64Decoder decoder = new BASE64Decoder();
    byte[] b1 = decoder.decodeBuffer(contextInfo);
    /** 执行解密操作 */
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < b1.length; i += 128) {
      byte[] doFinal = cipher.doFinal(ArrayUtils.subarray(b1, i, i + 128));
      sb.append(new String(doFinal));
    }
    String dataReturn = sb.toString();
    return dataReturn;
  }

  /**
   * 公钥验签
   *
   * @param strPublicKey 公钥文本
   * @param strSignVal 签名
   * @param strVerifyVal 待验证文本
   */
  public static boolean publicKeyVerify(String strPublicKey, String strSignVal,
      String strVerifyVal) {
    try {
      BASE64Decoder b64d = new BASE64Decoder();
      byte[] keyByte = b64d.decodeBuffer(strPublicKey);
      X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyByte);
      KeyFactory factory = KeyFactory.getInstance("RSA");
      PublicKey publicKey = factory.generatePublic(x509EncodedKeySpec);
      // 实例化
      Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
      // 初始化
      signature.initVerify(publicKey);
      // 更新
      signature.update(strVerifyVal.getBytes(ENCODEDING));
      // 验签
      return signature.verify(ByteUtil.hexToByte(strSignVal));
    } catch (Exception e) {

    }
    return false;
  }

  /**
   * 私钥签名
   *
   * @Author: guoleijie@shie.com.cn
   */
  public static String privateKeySign(String strPriKey, String strPlainVal) {
    try {
      byte[] plainText = strPlainVal.getBytes(ENCODEDING);
      BASE64Decoder b64d = new BASE64Decoder();
      byte[] keyByte = b64d.decodeBuffer(strPriKey);
      PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(keyByte);
      KeyFactory factory = KeyFactory.getInstance("RSA");
      PrivateKey privateKey = factory.generatePrivate(pkcs8EncodedKeySpec);
      // 实例化
      Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
      // 初始化，传入私钥
      signature.initSign(privateKey);
      // 更新
      signature.update(plainText);
      // 签名
      return ByteUtil.byteToHex(signature.sign());
    } catch (Exception e) {

    }
    return null;
  }
}
